package cn.edu.hit.joinsystem;

import cn.edu.hit.HttpRequestorWithTokenForJoinsystem;
import cn.edu.hit.core.Document;
import cn.edu.hit.core.Pair;
import cn.edu.hit.core.combine.CombineLoader;
import cn.edu.hit.core.conf.ConfigureLoader;
import cn.edu.hit.core.db.*;
import cn.edu.hit.core.message.MessageLoader;
import cn.edu.hit.kg.data.GraphData;
import cn.edu.hit.kg.entity.BaseNode;
import cn.edu.hit.kg.entity.Component;
import cn.edu.hit.kg.entity.Fault;
import cn.edu.hit.kg.entity.Signal;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.collections.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

import static cn.edu.hit.core.Adapter.VALUE;
import static cn.edu.hit.core.combine.CombineAdapter.*;
import static cn.edu.hit.core.message.MessageAdapter.*;

/**
 * Created by Wang on 2018/12/18.
 */
public class App2 {
    static Logger logger = LoggerFactory.getLogger(App2.class);

    public static void main(String[] args) {

        DataConnection connection = DataConnectionLoader.getInstance();
        DataReader dataReader = connection.getReader();
        DBReadHelper dbHelper = new DBReadHelper(dataReader);

        MessageLoader messageLoader = MessageLoader.getInstance();

        CombineLoader combineLoader = CombineLoader.getInstance();

        Set<Document> unitSet = dataReader.queryByTemplate((Filters.eq("type", "generator"))).stream()
                .collect(Collectors.toSet());//在mongo.data读取出的文件中，根据规则type=generator得到配置文件中的所有机组号

        ConfigureLoader configureLoader = ConfigureLoader.getInstance();
        Document conf = configureLoader.getBaseConfigure();
        long work_span = 10000;

        String WORK_SPAN = conf.getString("WORK_SPAN", "10000");
        String urlString = conf.getString("JOINSYSTEM_POST_URL", "http://172.16.45.249:8096/rsfs/faultData");

        try {
            work_span = Integer.parseInt(WORK_SPAN);
            if (work_span <= 500) {
                work_span = 500;
            }
        } catch (NumberFormatException ex) {
            System.err.println("配置文件不正确，" + WORK_SPAN + "应当为大于500的整数。 ");
        }

        String token_aquire_url = conf.getString("token_aquire_url", "http://222.171.52.120:11185/api/v1/authorization/auth");
        String token_aquire_user = conf.getString("token_aquire_user", "wangrp");
        String token_aquire_password = conf.getString("token_aquire_password", "Wrp123456");
        String token_refresh_url = conf.getString("token_refresh_url", "http://222.171.52.120:11185/api/v1/authorization/refresh/");

        String data_get_url = conf.getString("JOINSYSTEM_GET_URL", "http://172.16.45.250:8094/rsget/realtimeData/points/");

        //        HttpRequestorWithToken requestor = HttpRequestorWithToken.getInstance(token_aquire_url, token_aquire_user, token_aquire_password, token_refresh_url);
        HttpRequestorWithTokenForJoinsystem requestor = HttpRequestorWithTokenForJoinsystem.getInstance(token_aquire_url, token_aquire_user, token_aquire_password);

        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                long timestamp = System.currentTimeMillis();
                for (Document workUnit : unitSet) {
                    try {
                        String unitId = workUnit.getString("MachineNo");
                        String unit_id = workUnit.getObjectId("_id");
                        List<Document> documentStream = dbHelper.loadConfigure(unit_id, "signal");

                        String confKey = unitId + "working_condition";

//                        logger.info("confKey：{}", confKey);

                        String working_condition = conf.getString(confKey);

                        String url = String.format(data_get_url + working_condition + "/times?beginTime=%d&endTime=%d", timestamp - Integer.parseInt(WORK_SPAN), timestamp);

                        logger.info("工况信息请求url：{}", url);

                        String resultJson = requestor.doGet(url);

                        logger.info("工况信息返回结果：{}", resultJson);

                        JSONObject working_jsonObject = JSONObject.fromObject(resultJson);
                        JSONArray working_jsonArray = working_jsonObject.getJSONArray("data");

                        JSONObject jobj = working_jsonArray.getJSONObject(0);

                        Iterator<String> it = jobj.keys();

                        String value = "0.0";

                        while (it.hasNext()) {
                            String key = it.next();
                            value = jobj.getString(key);

                        }
                        if (value.equals("0.0")) {


//                        System.out.println(documentStream);  //取消输出
                            List<Map> signals = messageLoader.transfer(documentStream.stream().map(d -> (Map) d),
                                    d -> d.get(ID).toString(), d -> d.get(DATA_SOURCE).toString(), timestamp)
                                    .collect(Collectors.toList());


                            ((List<Document>) dataReader.queryByTemplate(
                                    Filters.and(
                                            Filters.eq("name", unit_id),
                                            Filters.eq("type", "package"))))
                                    .stream()
                                    .sorted(Comparator.comparing(x -> ((Document) x).getInteger("processStep")).reversed())
                                    .map(doc -> doc.getObjectId("_id"))
                                    .forEach(chain -> {
                                        List<Document> featureConfigStream = dbHelper.loadConfigure(chain, "feature");

                                        Map<String, Object> rawFeatures = signals.stream().collect(Collectors.groupingBy(
                                                document -> document.get(PORT_ID).toString(),
                                                Collectors.collectingAndThen(Collectors.toSet(), set -> set.stream().findFirst().get())
                                        ));

                                        List<Map> results = combineLoader.transfer(featureConfigStream.stream().map(d -> (Map) d),
                                                d -> d.get(ID).toString(), d -> d.get(COMBINE_STRATEGY).toString(), Pair.of(timestamp, rawFeatures)).collect(Collectors.toList());
                                        signals.addAll(results);
                                    });
                            List<Signal> rawFeatures = getKnowledgeSignals(signals);

                            GraphData graphData = GraphData.getInstance();
                            List<Map> results =
                                    graphData.getIdSetByLabel("Fault").stream().map(Fault::loadById)
//                                        .filter(fault -> fault.matchSignal(rawFeatures, timestamp, unitId))
                                            .peek(fault -> fault.matchSignal(rawFeatures, timestamp, unitId))
                                            .filter(fault -> fault.isMatched() || fault.isFinished(unitId))
                                            .map(fault -> fault.transferFaultToMap(unitId))
                                            .peek(map -> {
                                                map.put("timestamp", timestamp);
                                                if ((long) map.get("last_timestamp") == timestamp) {
                                                    map.put("last_timestamp", 0);
                                                }
                                            })
                                            .collect(Collectors.toList());

                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("timestamp", timestamp);
                            jsonObject.put("machine_name", workUnit.getString("MachineName"));
                            jsonObject.put("data", results);

                            Map nodes = new HashMap<>();
                            results.stream()
                                    .map(map -> (long) map.get("id"))
                                    .map(BaseNode::loadNodeById)
                                    .forEach(node -> nodes.put("" + node.getId(), node.toJson()));

                            results.stream()
                                    .map(map -> (long) map.get("id"))
                                    .flatMap(BaseNode::getAllSubNodes)
                                    .map(BaseNode::loadNodeById)
                                    .forEach(node -> nodes.put("" + node.getId(), node.toJson()));

                            jsonObject.put("node", nodes);
                            logger.info("发送数据：{}", jsonObject.toString());
                            String resultString = requestor.doPost(urlString, jsonObject.toString());
                            logger.info("返回结果：{}", resultString);
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }

                }
            }
        };

        Timer workTimer = new Timer();
        workTimer.schedule(task, 0, work_span);
    }

    public static List<Signal> getKnowledgeSignals(List<Map> signals) {
        List<Signal> rawFeatures = signals.stream()
                .filter(signal -> signal.containsKey("signalType"))
                .map(document -> {
                    Signal signal = new Signal();
                    signal.setFeatureType(document.get(FEATURE_TYPE).toString());
                    signal.setValue(document.get(VALUE));
                    Map component = Component.getByName(document.get(COMPONENT_NAME).toString());
                    signal.setComponent(component);
                    signal.setSource(document);
                    return signal;
                })
                .collect(Collectors.toList());

        List<Signal> rawSignals = signals.stream()
                .filter(signal -> !signal.containsKey("signalType"))
                .map(document -> {
                    Signal signal = new Signal();
                    signal.setFeatureType(document.get("portName").toString());
                    signal.setValue(document.get(VALUE));
                    signal.setComponent(null);
                    signal.setSource(document);
                    return signal;
                }).collect(Collectors.toList());

        return ListUtils.union(rawFeatures, rawSignals);
    }
}
